import { HealthCheckWithScreenTask, V3proLastErrCache } from "./health.check.class";
import { ScanBoardKey, V3proSubjectMessage } from "../model/v3pro.model";
import {
  V3proScreen,
  V3proScreenAllStatus,
  V3proSendBoxScanBoard,
} from "../../../api/v3pro-api/v3pro.api.response.model";
import { V3proAlertMessageErrTypeEnum } from "../model/v3pro.enum";
import { V3proScreenLayoutHelper } from "../helper/v3pro.screen.layout.helper";
import { appConfig } from "../../../configs/env.config.load";
import { AppCache } from "../../../utils/cache.util";
import { V3proAllStatusLambda } from "../helper/v3pro.all.status.lambda.helper";
import { V3proFileHelper } from "../helper/v3pro.file.helper";
import { V3proScreenImageHelper } from "../helper/v3pro.screen.image.helper";
import { randomUUID } from "node:crypto";

/**
 * 扫描板异常重启
 *
 * 是否支持阈值设置： N
 *
 * 查询周期:
 * 由扫描板主动上报
 *
 * 告警产生的原因:
 * 扫描板一小时内reset次数>3
 * 机箱转接板或扫描板上的电子器件故障或者电源有问题
 *
 * 异常现象:
 * 机箱显示随机出现花屏、画面卡顿
 *
 * 维修建议:
 * 依次排查电源、转接板、扫描板等硬件
 *
 * 告警级别: 紧急
 */

const caches = new Map<string, AppCache>();
const lastTime = new Map<string, number>();

const errCache = new V3proLastErrCache<ScanBoardKey>();

export class V3proCheckScanboardErrorRestartTask extends HealthCheckWithScreenTask<ScanBoardKey[]> {
  async checkResult(
    keyParams: ScanBoardKey[],
    screenId: string,
    allStatus: V3proScreenAllStatus,
    screenLayoutHelper: V3proScreenLayoutHelper,
  ): Promise<V3proSubjectMessage> {
    const message = new V3proSubjectMessage();
    if (keyParams.length === 0) return message;
    message.setErrStatus();
    keyParams.forEach((board) => screenLayoutHelper.setScanBoardErrById(board.id, 0, 0));
    message.files = [
      await V3proFileHelper.scanBoardKey2File(keyParams),
      await new V3proScreenImageHelper(screenLayoutHelper, ["scanBoard"])
        .draw()
        .export2AlertMessageFile(),
    ];
    return message;
  }

  private __setRestart(scanBoard: V3proSendBoxScanBoard) {
    const {
      deviceInfo: { id },
      status: {
        runStatus: { uptimeS },
      },
    } = scanBoard;
    if (!lastTime.has(id)) {
      lastTime.set(id, uptimeS);
      return;
    }
    const last = lastTime.get(id)!;
    lastTime.set(id, uptimeS);
    if (last <= uptimeS) return;
    if (!caches.has(id)) {
      caches.set(id, new AppCache("1h"));
    }
    const cache = caches.get(id)!;
    cache.set(randomUUID(), true);
  }

  private __isErrRestart(scanBoard: V3proSendBoxScanBoard): boolean {
    const {
      deviceInfo: { id },
      status: {
        runStatus: { uptimeS },
      },
    } = scanBoard;
    if (!caches.has(id)) return false;
    return caches.get(id)!.size() > 2;
  }

  async genKeyParams(
    allStatus: V3proScreenAllStatus,
    screen: V3proScreen,
    screenLayoutHelper: V3proScreenLayoutHelper,
  ): Promise<ScanBoardKey[]> {
    const handler = (scanBoard: V3proSendBoxScanBoard) => {
      if (!V3proAllStatusLambda.communicationOK(scanBoard)) return false;
      this.__setRestart(scanBoard);
      return this.__isErrRestart(scanBoard);
    };
    const [errs, normals] = V3proAllStatusLambda.filterScanBoardsWithRemove(
      allStatus,
      handler,
      V3proAllStatusLambda.communicationOK,
    );
    return errCache.mergeCache(
      errs.map(ScanBoardKey.build),
      normals.map(ScanBoardKey.build),
      screen.id,
      (s) => s.id,
    );
  }

  genSRMqttTopic(
    message: V3proSubjectMessage,
    screenId: string,
    allStatus: V3proScreenAllStatus,
  ): string {
    return `notify/alert/ssads/device-led-disp:scanboard-abnormal-reboot/${screenId}`;
  }

  getV3proAlertMessage(): V3proAlertMessageErrTypeEnum {
    return V3proAlertMessageErrTypeEnum.SCAN_BOARD_ERROR_RESET;
  }

  isNeedUploadFile(
    message: V3proSubjectMessage,
    screenId: string,
    allStatus: V3proScreenAllStatus,
  ): boolean {
    return message.isErrStatus();
  }

  isReportEnabled(keyParams: any, screenId: string): boolean {
    return appConfig.v3pro.errEnable.scanBoardErrReset;
  }
}
